package com.ruoyi.central.publisher.subscription.material;

import com.ruoyi.central.domain.TopCentralMaterial;
import com.ruoyi.central.domain.TopCentralProduct;
import com.ruoyi.central.enums.MaterialStatusEnum;
import com.ruoyi.central.publisher.event.TopCentralMaterialEvent;
import com.ruoyi.central.service.ITopCentralMaterialService;
import com.ruoyi.central.service.ITopCentralProductService;
import com.ruoyi.common.enums.common.TaskStatusEnum;
import com.ruoyi.common.exception.base.service.ServiceException;
import com.ruoyi.common.utils.CollectionUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.EnumUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.util.Assert;

/**
 * @Classname MaterialEventSubsctiptionForProduct
 * @Author: sunluquan
 * @Date: 2022/6/22 10:32
 * @Description TODO
 * 物料对象 事件相关订阅  为 产品对象
 */
@Order(2)
@Component
public class MaterialEventSubscriptionForProduct {

    @Autowired
    private ITopCentralProductService productService;

    @Autowired
    private ITopCentralMaterialService materialService;
    /**
     * 产品对象 订阅 物料新增事件
     * 如果新增的物料对象 没有最终的产品绑定 则新增 产品实体对象
     * @param event
     */
    @TransactionalEventListener(value= TopCentralMaterialEvent.class,phase = TransactionPhase.BEFORE_COMMIT,condition = "#event.getSignEnum().name()=='INSERT'")
    public void insertEvent(TopCentralMaterialEvent event){

        TopCentralMaterial source = event.getSource();

        String batchNoOfMaterial = source.getBatchNo();

        if(StringUtils.isNotNull(productService.selectUsableByBatchNo(batchNoOfMaterial,TopCentralProduct::getId))){
            return;
        }

        Integer productTypeId = source.getProductTypeId();

        TopCentralProduct productOfInsert = new TopCentralProduct();
        productOfInsert.setBatchNo(batchNoOfMaterial);
        productOfInsert.setTypeId(productTypeId);
        productOfInsert.setSyntheticStatus(TaskStatusEnum.NOT_START.getValue());

        productService.insert(productOfInsert);

    }

    /**
     * 只处理后端触发的修改
     * 判断修改的物料状态  只处理修改物料状态为 已使用、已合并
     * 处理修改为 已使用 状态的物料对象：判断产品合并状态是否为未开始 如果为未开始 修改为执行中
     * 处理修改为 已合并 状态的物料对象：判断物料对象的父物料类型 是否为当前产品 是---》修改产品合并状态 为 已完成
     * @param event
     */
    @TransactionalEventListener(value= TopCentralMaterialEvent.class,phase = TransactionPhase.BEFORE_COMMIT,condition = "#event.getSignEnum().name()=='UPDATE' and #event.isOperationType()")
    public void updateEvent(TopCentralMaterialEvent event){

        TopCentralMaterial newMaterial = event.isContainer()? CollectionUtils.getFirst(event.getSources()):event.getSource();

        String materialId = newMaterial.getId();

        if(StringUtils.isNull(newMaterial.getMaterialStatus())){
            return ;
        }

        MaterialStatusEnum oldMaterialStatus ;
        MaterialStatusEnum newMaterialStatus ;
        TopCentralMaterial oldMaterial = newMaterial.getOldMaterial();

        if(StringUtils.isNull(oldMaterial)){
            oldMaterial = materialService.selectUsableById(materialId,TopCentralMaterial::getId,TopCentralMaterial::getParentTypeId,TopCentralMaterial::getMaterialStatus);
            Assert.notNull(oldMaterial,StringUtils.format("未找到物料编号为：{} ，的数据或数据不可用！",materialId));
        }

        oldMaterialStatus = EnumUtils.toEnum(MaterialStatusEnum.class,oldMaterial.getMaterialStatus());
        newMaterialStatus = EnumUtils.toEnum(MaterialStatusEnum.class,newMaterial.getMaterialStatus());

        if(oldMaterialStatus==newMaterialStatus){
            return;
        }

        if(!oldMaterialStatus.isTransition(newMaterialStatus)){
            throw new ServiceException("物料编号为：{} 的物料状态转换失败，{} 不能过渡到 {} 状态！",
                    materialId,oldMaterialStatus.getDescription(),newMaterialStatus.getDescription());
        }

        if(newMaterialStatus == MaterialStatusEnum.USE_OF_STATUS || newMaterialStatus == MaterialStatusEnum.COMBINED_OF_STATUS){

            String batchNo = newMaterial.getBatchNo();

            TopCentralProduct product = productService.selectUsableByBatchNo(batchNo,TopCentralProduct::getId,TopCentralProduct::getBatchNo,TopCentralProduct::getTypeId,TopCentralProduct::getSyntheticStatus);

            Assert.notNull(product,StringUtils.format("物料编号为：{} ， 物料批次号为：{} 的产品数据未找到或不存在！"));

            switch (newMaterialStatus){
                //检测物料对象 的 物料状态 变更为 使用中
                //1.判断当前产品对象合成状态是否为未开始
                //2.如果产品对象的合成状态为未开始  修改为 执行中
                case USE_OF_STATUS:

                    if(EnumUtils.equals(TaskStatusEnum.NOT_START,product.getSyntheticStatus())){

                        fillAndUpdateForProduct(product,TaskStatusEnum.EXECUTING);

                    }

                    break;

                //检测物料对象 的 物料状态 变更为已合并
                //一般变更为已合并都是集合数据
                //1.判断当前物料对象 的父类型编号 是否等于 产品的类型对象
                //2.如果等于 说明当前产品全部操作完毕
                //3.修改 产品对象的合成状态 修改为 已完成
                case COMBINED_OF_STATUS:

                    Integer parentTypeId = oldMaterial.getParentTypeId();

                    if(StringUtils.equals(parentTypeId,product.getTypeId())){

                        fillAndUpdateForProduct(product,TaskStatusEnum.EXECUTED_FINISH);

                    }
                    break;
            }
        }
    }

    /**
     * 根据模板数据填充修改 产品对象
     * @param template
     * @param targetTaskStatus
     */
    private void fillAndUpdateForProduct(TopCentralProduct template,TaskStatusEnum targetTaskStatus){

        TaskStatusEnum odlTaskStatus = EnumUtils.toEnum(TaskStatusEnum.class, template.getSyntheticStatus());
        if(!odlTaskStatus.isTransition(targetTaskStatus)){
            throw new ServiceException("产品批次号：{} 的合并状态不能从 {} 过渡到 {} ！",template.getBatchNo(),odlTaskStatus.getDescription(),targetTaskStatus.getDescription());
        }

        TopCentralProduct productOfUpdate = new TopCentralProduct();

        productOfUpdate.setId(template.getId());

        productOfUpdate.setSyntheticStatus(targetTaskStatus.getValue());

        productService.updateById(productOfUpdate);
    }
}
